import asyncio
from typing import Dict, Optional, Callable, Any
from collections import defaultdict


class TaskManager:
    def __init__(self):
        # 存储任务信息: {task_id: {progress: int, total: int}}
        self.tasks: Dict[str, Dict[str, int]] = {}
        # 存储活跃的导出任务及其取消函数
        self.active_exports: Dict[str, Callable[[], Any]] = {}
        # 事件监听器: {event_name: [callback_function, ...]}
        self.event_listeners = defaultdict(list)

    def on(self, event_name: str):
        """注册事件监听器（支持装饰器语法）"""
        def decorator(callback: Callable):
            self.event_listeners[event_name].append(callback)
            return callback
        return decorator

    async def emit(self, event_name: str, *args, **kwargs):
        """触发事件，异步执行所有监听器"""
        for callback in self.event_listeners.get(event_name, []):
            try:
                # 处理同步和异步回调
                if asyncio.iscoroutinefunction(callback):
                    await callback(*args, **kwargs)
                else:
                    callback(*args, **kwargs)
            except Exception as e:
                print(f"Error in {event_name} event handler: {str(e)}")

    def create_task(self, task_id: str, total: int) -> str:
        """创建新任务"""
        if task_id in self.tasks:
            print(f"Task {task_id} already exists, overwriting")

        self.tasks[task_id] = {
            "progress": 0,
            "total": total
        }

        # 触发进度事件
        asyncio.create_task(self.emit('progress', task_id, 0))
        return task_id

    def update_progress(self, task_id: str, processed: int):
        """更新任务进度"""
        if task_id not in self.tasks:
            print(f"Task {task_id} not found, cannot update progress")
            return

        task = self.tasks[task_id]
        task["progress"] = processed

        # 计算进度百分比，确保不超过100%
        progress_percent = min(int((task["progress"] / task["total"]) * 100), 100)

        # 触发进度事件
        asyncio.create_task(self.emit('progress', task_id, progress_percent))

    def complete_task(self, task_id: str):
        """标记任务为完成"""
        if task_id not in self.tasks:
            print(f"Task {task_id} not found, cannot complete")
            return

        task = self.tasks[task_id]
        task["progress"] = task["total"]

        # 触发100%进度事件
        asyncio.create_task(self.emit('progress', task_id, 100))
        asyncio.create_task(self.emit('complete', task_id))

        # 延迟1.5秒删除任务，确保前端能接收到100%进度
        async def delayed_cleanup():
            await asyncio.sleep(1.5)
            if task_id in self.tasks:
                del self.tasks[task_id]
            if task_id in self.active_exports:
                del self.active_exports[task_id]

        asyncio.create_task(delayed_cleanup())

    def cancel_task(self, task_id: str):
        """取消任务"""
        if task_id not in self.tasks:
            print(f"Task {task_id} not found, cannot cancel")
            return

        # 触发取消进度事件
        asyncio.create_task(self.emit('progress', task_id, -1))
        asyncio.create_task(self.emit('cancel', task_id))

        # 取消可能存在的导出任务
        if task_id in self.active_exports:
            try:
                self.active_exports[task_id]()
            except Exception as e:
                print(f"Error canceling export {task_id}: {str(e)}")

        # 延迟1.5秒删除任务
        async def delayed_cleanup():
            await asyncio.sleep(1.5)
            if task_id in self.tasks:
                del self.tasks[task_id]
            if task_id in self.active_exports:
                del self.active_exports[task_id]

        asyncio.create_task(delayed_cleanup())

    def get_progress(self, task_id: str) -> int:
        """获取任务当前进度"""
        if task_id not in self.tasks:
            return -1

        task = self.tasks[task_id]
        return min(int((task["progress"] / task["total"]) * 100), 100)

    def add_active_export(self, task_id: str, cancel_fn: Callable[[], Any]):
        """添加活跃的导出任务及其取消函数"""
        self.active_exports[task_id] = cancel_fn

    def cancel_active_export(self, task_id: str) -> bool:
        """取消活跃的导出任务"""
        if task_id in self.active_exports:
            try:
                self.active_exports[task_id]()
                del self.active_exports[task_id]
                return True
            except Exception as e:
                print(f"Error canceling active export {task_id}: {str(e)}")
        return False


# 创建单例实例
task_manager = TaskManager()


# 默认错误处理
@task_manager.on('error')
def handle_task_error(task_id: str, error: Exception):
    print(f"Task {task_id} error: {str(error)}")
